package cn.com.cifi.mars.util;

import cn.com.cifi.mars.bean.vo.price.PriceExcelExportVO;
import cn.com.cifi.mars.bean.vo.signPlan.DmAnalyticalVo;
import cn.com.cifi.mars.common.enums.PriceReportGroupCodeEnum;
import cn.com.cifi.mars.constant.Constants;
import cn.com.cifi.mars.constant.OrgTypeEunm;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.hssf.usermodel.*;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
public class PriceValueReportTemplate {

    private static final String TEMPLATE_PATH = "/template/price_value.xls";

    private HSSFWorkbook workbook;

    private HSSFSheet sheet;

    /**
     * 楼栋以及面积段 模板行索引
     */
    private int baseRow1Index = 3;


    /**
     * 楼栋以及面积段 模板行索引
     */
    private int baseRow2Index = 4;

    /**
     * 数据模板行 - 楼栋以及面积段
     */
    private HSSFRow baseRow1;


    /**
     * 数据模板行 - 楼栋及以上
     */
    private HSSFRow baseRow2;

    /**
     * 默认sheet索引
     */
    private int defaultSheetIndex = 0;


    /**
     * 数据开始行索引
     */
    private int dataBeginRow = 4;

    /**
     * 当前行标
     */
    private int currentDataRowCursor = dataBeginRow;

    /**
     * 基本信息结束列标
     */
    private int baseInfoEndColumn = 36;


    /**
     * 数据模板行
     */
    private HSSFCellStyle cellStyle;
    private HSSFCellStyle cellStyle1;
    private HSSFCellStyle cellStyle2;
    private HSSFCellStyle cellStyle3;
    private HSSFCellStyle cellStyle4;
    private HSSFCellStyle cellStyle5;
    private HSSFCellStyle cellStyle6;
    private HSSFCellStyle cellStyle7;
    private HSSFCellStyle cellStyle8;
    private HSSFCellStyle cellStyle9;
    private HSSFCellStyle cellStyle10;

    /**
     * 由于一开始模板没有需要根据不同级别区分不同样式的需求
     * 现在有了这种需求，直接改方法对原代码改动太大
     * 因此使用全局变量控制当前的组织机构类型
     */
    private OrgTypeEunm currentType;

    public PriceValueReportTemplate() {
        try {
            InputStream tempInputStream = PriceReportTemplate.class.getResourceAsStream(TEMPLATE_PATH);
            if (tempInputStream != null) {
                workbook = new HSSFWorkbook(tempInputStream);
                sheet = workbook.getSheetAt(defaultSheetIndex);
                //样式模板行
                baseRow1 = sheet.getRow(baseRow1Index);

                cellStyle1=sheet.getRow(2).getCell(0).getCellStyle();//汇总str
                cellStyle2=sheet.getRow(3).getCell(0).getCellStyle();

                cellStyle3=sheet.getRow(2).getCell(4).getCellStyle();//汇总%
                cellStyle4=sheet.getRow(3).getCell(4).getCellStyle();

                cellStyle5=sheet.getRow(2).getCell(17).getCellStyle();//汇总date
                cellStyle6=sheet.getRow(3).getCell(17).getCellStyle();

                cellStyle7=sheet.getRow(2).getCell(20).getCellStyle();//汇总int
                cellStyle8=sheet.getRow(3).getCell(20).getCellStyle();

                cellStyle9=sheet.getRow(2).getCell(21).getCellStyle();//汇总double
                cellStyle10=sheet.getRow(3).getCell(21).getCellStyle();
            }
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            throw new RuntimeException(e);
        }
    }

    public void setSheetName(String name){
        workbook.setSheetName(defaultSheetIndex,name);
    }


    /**
     * 批量插入行
     *
     * @param list
     */
    public synchronized void appendRows(List<PriceExcelExportVO> list) {
        for (PriceExcelExportVO priceVo : list) {
            this.appendRow(priceVo);
        }
    }

    public void copyCellStyle(HSSFCell from, HSSFCell to) {
        if (from != null && to != null && from != to && from.getCellStyle() != null) {
            to.setCellStyle(from.getCellStyle());
        }
    }

    /**
     * 插入行
     *
     * @param priceVO
     */
    public synchronized void appendRow(PriceExcelExportVO priceVO) {
        HSSFRow row = sheet.getRow(currentDataRowCursor);
        if (row == null) {
            row = sheet.createRow(currentDataRowCursor);
        }
        row.setHeightInPoints(Constants.HEIGHT_POINTS);

        AtomicInteger index = new AtomicInteger(-1);

        updateCellStyle(priceVO,"text");
        this.appendCell(row, index.addAndGet(1), priceVO.getProjectName());
        this.appendCell(row, index.addAndGet(1), priceVO.getProjectCode());

        this.appendCell(row, index.addAndGet(1), priceVO.getStageName());
        this.appendCell(row, index.addAndGet(1), priceVO.getStageCode());

        updateCellStyle(priceVO,"equityRatio");
        this.appendCell(row, index.addAndGet(1), priceVO.getStageEquityRatio());

        updateCellStyle(priceVO,"text");
        this.appendCell(row, index.addAndGet(1), priceVO.getIsMarket());
        this.appendCell(row, index.addAndGet(1), priceVO.getPartTable());

        this.appendCell(row, index.addAndGet(1), priceVO.getGroupName());

        this.appendCell(row, index.addAndGet(1), priceVO.getProProductName());
        this.appendCell(row, index.addAndGet(1), priceVO.getProProductCode());
        this.appendCell(row, index.addAndGet(1), priceVO.getProductName());
        this.appendCell(row, index.addAndGet(1), priceVO.getProductCode());

        this.appendCell(row, index.addAndGet(1), priceVO.getBuildName());

        this.appendCell(row, index.addAndGet(1), priceVO.getBusinessType());
        this.appendCell(row, index.addAndGet(1), priceVO.getFreeType());
        this.appendCell(row, index.addAndGet(1), priceVO.getProType());
        this.appendCell(row, index.addAndGet(1), priceVO.getAreaPart());

        updateCellStyle(priceVO,"date");
        if( priceVO.getSupplyTime() != null){
            this.appendCell(row, index.addAndGet(1), ReportUtils.toString(priceVO.getSupplyTime()));
        }else{
            this.appendCell(row, index.addAndGet(1), "");
        }
        if( priceVO.getSupplyTimeVirtual() != null){
            this.appendCell(row, index.addAndGet(1), ReportUtils.toString(priceVO.getSupplyTimeVirtual()));
        }else{
            this.appendCell(row, index.addAndGet(1), "");
        }
        if( priceVO.getSupplyTimeActual() != null){
            this.appendCell(row, index.addAndGet(1), ReportUtils.toString(priceVO.getSupplyTimeActual()));
        }else{
            this.appendCell(row, index.addAndGet(1), "");
        }

        updateCellStyle(priceVO,"number");
        if (priceVO.getType().equals(OrgTypeEunm.ORG_PRODUCT.getKey())
            || priceVO.getType().equals(OrgTypeEunm.ORG_BUILD.getKey())
            || priceVO.getType().equals(OrgTypeEunm.ORG_HOUSE_PACKAGE.getKey())
            || priceVO.getType().equals(OrgTypeEunm.ORG_SALE_PACKAGE.getKey())
            || priceVO.getType().equals(OrgTypeEunm.ORG_NOT_SALE_PACKAGE.getKey())
            || priceVO.getType().equals(OrgTypeEunm.ORG_SALING_PARKING.getKey())
            || priceVO.getType().equals(OrgTypeEunm.ORG_NOT_SALING_PARKING.getKey())){
            this.appendCell(row, index.addAndGet(1), Double.parseDouble(priceVO.getNum()==null?"0":priceVO.getNum().replace(",","")));
        }else{
            this.appendCell(row, index.addAndGet(1), priceVO.getNum());
        }

        updateCellStyle(priceVO,"rate");
        this.appendCell(row, index.addAndGet(1), Double.parseDouble(priceVO.getArea()==null?"0":priceVO.getArea()));

        updateCellStyle(priceVO,"number");
        if (priceVO.getType().equals(OrgTypeEunm.ORG_PRODUCT.getKey())
                || priceVO.getType().equals(OrgTypeEunm.ORG_BATCH.getKey())
                || priceVO.getType().equals(OrgTypeEunm.ORG_BUILD.getKey())
                || priceVO.getType().equals(OrgTypeEunm.ORG_HOUSE_PACKAGE.getKey())
                || priceVO.getType().equals(OrgTypeEunm.ORG_SALE_PACKAGE.getKey())
                || priceVO.getType().equals(OrgTypeEunm.ORG_NOT_SALE_PACKAGE.getKey())
                || priceVO.getType().equals(OrgTypeEunm.ORG_SALING_PARKING.getKey())
                || priceVO.getType().equals(OrgTypeEunm.ORG_NOT_SALING_PARKING.getKey())){

            this.appendCell(row, index.addAndGet(1),  Double.parseDouble(priceVO.getAveragePrice()==null?"0":priceVO.getAveragePrice().replace(",","")));
            this.appendCell(row, index.addAndGet(1),  Double.parseDouble(priceVO.getPrice()==null?"0":priceVO.getPrice().replace(",","")));
        }else{
            this.appendCell(row, index.addAndGet(1), priceVO.getAveragePrice());
            this.appendCell(row, index.addAndGet(1), priceVO.getPrice());
        }

        this.appendCell(row, index.addAndGet(1),  Double.parseDouble(priceVO.getNotNum()==null?"0":priceVO.getNotNum().replace(",","")));
        this.appendCell(row, index.addAndGet(1),  Double.parseDouble(priceVO.getNotPrice()==null?"0":priceVO.getNotPrice().replace(",","")));

        currentDataRowCursor++;
    }

    private void makeGroupColumn(Map<String, Object> map, HSSFRow row, AtomicInteger index,PriceReportGroupCodeEnum groupCodeEnum,OrgTypeEunm orgTypeEunm) {
        BigDecimal roomCount = MathUtils.newBigDecimal((String) map.get(groupCodeEnum.toFormatString("roomCount")));
        BigDecimal carPlateCount = MathUtils.newBigDecimal((String) map.get(groupCodeEnum.toFormatString("carPlateCount")));
        BigDecimal area = MathUtils.newBigDecimal((String) map.get(groupCodeEnum.toFormatString("area")));
        BigDecimal roomTotalPrice = MathUtils.newBigDecimal((String) map.get(groupCodeEnum.toFormatString("roomTotalPrice")));
        BigDecimal carPlateTotalPrice = MathUtils.newBigDecimal((String) map.get(groupCodeEnum.toFormatString("carPlateTotalPrice")));
        BigDecimal totalPrice = MathUtils.bigDecimalAdd(roomTotalPrice,carPlateTotalPrice);
        BigDecimal roomAvgPrice = area.doubleValue() > 0?roomTotalPrice.divide(area,0, RoundingMode.HALF_UP): BigDecimal.ZERO;
        BigDecimal carAvgPrice = carPlateCount.intValue() > 0?carPlateTotalPrice.divide(carPlateCount,0,RoundingMode.HALF_UP):BigDecimal.ZERO;
        String isParkingStr = (String) map.get(groupCodeEnum.toFormatString("isParking"));
        Boolean isParking = "1".equals(isParkingStr);
        if (orgTypeEunm == OrgTypeEunm.ORG_GROUP || orgTypeEunm == OrgTypeEunm.ORG_STAGE || orgTypeEunm == OrgTypeEunm.ORG_PRODUCTF){
            this.appendCell(row, index.addAndGet(1), ReportUtils.split(roomCount, carPlateCount));
        }else {
            this.appendCell(row, index.addAndGet(1), ReportUtils.toString(isParking == null || !isParking ? roomCount:carPlateCount));
        }
        this.appendCell(row, index.addAndGet(1), ReportUtils.toString(area.setScale(2,RoundingMode.HALF_UP)));
        if (orgTypeEunm == OrgTypeEunm.ORG_GROUP || orgTypeEunm == OrgTypeEunm.ORG_STAGE || orgTypeEunm == OrgTypeEunm.ORG_PRODUCTF){
            this.appendCell(row, index.addAndGet(1), ReportUtils.split(roomAvgPrice,carAvgPrice));
        }else {
            this.appendCell(row, index.addAndGet(1), ReportUtils.toString(isParking == null || !isParking ? roomAvgPrice:carAvgPrice));
        }
        if (orgTypeEunm == OrgTypeEunm.ORG_GROUP || orgTypeEunm == OrgTypeEunm.ORG_STAGE || orgTypeEunm == OrgTypeEunm.ORG_PRODUCTF){
            this.appendCell(row, index.addAndGet(1), ReportUtils.split(totalPrice.divide(MathUtils.NUM_10000,0,RoundingMode.HALF_UP),roomTotalPrice.divide(MathUtils.NUM_10000,0,RoundingMode.HALF_UP),carPlateTotalPrice.divide(MathUtils.NUM_10000,0,RoundingMode.HALF_UP)));
        }else {
            this.appendCell(row, index.addAndGet(1), ReportUtils.toString(totalPrice.divide(MathUtils.NUM_10000,0,RoundingMode.HALF_UP)));
        }

    }

    //修改单元格样式
    private void updateCellStyle(PriceExcelExportVO priceVO, String type) {
        if(priceVO.getType().equals(OrgTypeEunm.ORG_STAGE.getKey()) ||
                priceVO.getType().equals(OrgTypeEunm.ORG_GROUP.getKey()) ||
                priceVO.getType().equals(OrgTypeEunm.ORG_PRODUCT.getKey())){
            switch (type) {
                case "text":
                    cellStyle = cellStyle1;
                    break;
                case "equityRatio":
                    cellStyle = cellStyle3;
                    break;
                case "date":
                    cellStyle = cellStyle5;
                    break;
                case "number":
                    cellStyle = cellStyle7;
                    break;
                case "rate":
                    cellStyle = cellStyle9;
                    break;
            }
        }else {
            switch (type) {
                case "text":
                    cellStyle = cellStyle2;
                    break;
                case "equityRatio":
                    cellStyle = cellStyle4;
                    break;
                case "date":
                    cellStyle = cellStyle6;
                    break;
                case "number":
                    cellStyle = cellStyle8;
                    break;
                case "rate":
                    cellStyle = cellStyle10;
                    break;
            }
        }
    }

    /**
     * 插入列
     *
     * @param row
     * @param index
     * @param value
     */
    public synchronized void appendCell(HSSFRow row, int index, String value) {
        HSSFCell cell = row.getCell(index);
        if (cell == null) {
            cell = row.createCell(index);
        }
        cell.setCellStyle(cellStyle);
        ReportUtils.setCellValue(cell,value);
    }


    /**
     * 插入列
     *
     * @param row
     * @param index
     * @param value
     */
    public synchronized void appendCell(HSSFRow row, int index, Double value) {
        HSSFCell cell = row.getCell(index);
        if (cell == null) {
            cell = row.createCell(index);
        }
        cell.setCellStyle(cellStyle);
        cell.setCellValue(value);
    }


    /**
     * 导出
     *
     * @param outputStream
     * @throws IOException
     */
    public void write(OutputStream outputStream) throws IOException {
        //删除掉模板行
        int startRow = baseRow2Index;
        int lastRowNum = sheet.getLastRowNum();
        if (startRow <= lastRowNum) {
            sheet.shiftRows(startRow, lastRowNum,-2);
        }else {
            sheet.removeRow(baseRow1);
            sheet.removeRow(baseRow2);
        }
        workbook.write(outputStream);
    }

}
